package it.antonio.ilpizze.db;

import it.antonio.ilpizze.db.Record;
import it.antonio.ilpizze.func.Predicate;

public abstract class QueryPredicates implements Predicate<Record> {
	public static QueryPredicates all(){
		return new QueryPredicates() {

			@Override
			public boolean match(Record elem) {
				return true;
			}
		};
	} 
	
	public static QueryPredicates field(final String name, final Object value){
		return new QueryPredicates() {

			@Override
			public boolean match(Record record) {
				return value.equals(record.get(name));
			}
		};
	}
	
	public static QueryPredicates fieldIsNotNull(final String name){
		return new QueryPredicates() {

			@Override
			public boolean match(Record record) {
				return record.get(name) != null;
			}
		};
	}
	public static QueryPredicates match(final Predicate<Record> pred){
		return new QueryPredicates() {

			@Override
			public boolean match(Record record) {
				return pred.match(record);
			}
		};
	}
	
	public AndQueryBuilder and(){
		return new AndQueryBuilder(this);
	}
	
	public OrQueryBuilder or(){
		return new OrQueryBuilder(this);
	}
	
	
	public class AndQueryBuilder {
		private QueryPredicates query;

		public AndQueryBuilder(QueryPredicates query) {
			this.query = query;
		}
		
		public QueryPredicates field(final String name, final Object value){
			return and(query, QueryPredicates.field(name, value));
		}
		
		public QueryPredicates fieldIsNotNull(final String name){
			return and(query, QueryPredicates.fieldIsNotNull(name));
		}
		
		public QueryPredicates match(final Predicate<Record> pred){
			return and(query, QueryPredicates.match(pred));
		}
		
	}
	
	public class OrQueryBuilder {
		private QueryPredicates query;

		public OrQueryBuilder(QueryPredicates query) {
			this.query = query;
		}
		
		public QueryPredicates field(final String name, final Object value){
			return or(query, QueryPredicates.field(name, value));
		}
		
		public QueryPredicates fieldIsNotNull(final String name){
			return or(query, QueryPredicates.fieldIsNotNull(name));
		}
		
		public QueryPredicates match(final Predicate<Record> pred){
			return or(query, QueryPredicates.match(pred));
		}
		
	}
	
	private static QueryPredicates and(final QueryPredicates first, final QueryPredicates second){
		return new QueryPredicates() {

			@Override
			public boolean match(Record record) {
				if(!first.match(record)) return false;
				return second.match(record);
			}
		};
		
	}
	
	private static QueryPredicates or(final QueryPredicates first, final QueryPredicates second){
		return new QueryPredicates() {

			@Override
			public boolean match(Record record) {
				if(first.match(record)) return true;
				return second.match(record);
			}
		};
	}
	
}
